Java 26-Day Course - Day 15: Collections - List

Day 15: Collections - List

The Java Collections Framework is a library of data structures for efficiently storing and managing data. Unlike arrays, collections dynamically resize and provide various utility methods. Today we focus on the most commonly used List interface.

ArrayList Basics

An array-based list with fast index-based access as its strength.

import java.util.ArrayList;
import java.util.List;

public class ArrayListBasic {
    public static void main(String[] args) {
        // Create an ArrayList
        List<String> fruits = new ArrayList<>();

        // Add elements
        fruits.add("Apple");
        fruits.add("Banana");
        fruits.add("Grape");
        fruits.add("Strawberry");

        // Add at a specific position
        fruits.add(1, "Orange");

        // Access elements
        System.out.println("First: " + fruits.get(0));           // Apple
        System.out.println("Size: " + fruits.size());              // 5
        System.out.println("Contains Grape? " + fruits.contains("Grape")); // true
        System.out.println("Grape index: " + fruits.indexOf("Grape"));     // 3

        // Modify an element
        fruits.set(0, "Green Apple");

        // Remove elements
        fruits.remove("Banana");       // Remove by value
        fruits.remove(0);              // Remove by index

        // Iteration methods
        // 1. for-each
        for (String fruit : fruits) {
            System.out.print(fruit + " ");
        }
        System.out.println();

        // 2. forEach + lambda
        fruits.forEach(fruit -> System.out.print(fruit + " "));
        System.out.println();

        // Check if empty
        System.out.println("Is empty? " + fruits.isEmpty());

        // Clear all
        fruits.clear();
        System.out.println("Size after clear: " + fruits.size());
    }
}

ArrayList vs LinkedList

Learn how to choose the appropriate list implementation for different situations.

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

public class ListComparison {
    public static void main(String[] args) {
        // ArrayList: uses an array internally
        // - Index access: O(1) fast
        // - Middle insert/delete: O(n) slow (element shifting required)
        List<Integer> arrayList = new ArrayList<>();

        // LinkedList: uses a doubly linked list internally
        // - Index access: O(n) slow
        // - Front/back insert/delete: O(1) fast
        List<Integer> linkedList = new LinkedList<>();

        // Performance comparison: adding data
        long start;

        // ArrayList: add to end
        start = System.nanoTime();
        for (int i = 0; i < 100000; i++) {
            arrayList.add(i);
        }
        System.out.println("ArrayList append: " +
            (System.nanoTime() - start) / 1_000_000 + "ms");

        // LinkedList: add to end
        start = System.nanoTime();
        for (int i = 0; i < 100000; i++) {
            linkedList.add(i);
        }
        System.out.println("LinkedList append: " +
            (System.nanoTime() - start) / 1_000_000 + "ms");

        // Index access comparison
        start = System.nanoTime();
        for (int i = 0; i < 10000; i++) {
            arrayList.get(50000);
        }
        System.out.println("ArrayList index access: " +
            (System.nanoTime() - start) / 1_000_000 + "ms");

        start = System.nanoTime();
        for (int i = 0; i < 10000; i++) {
            linkedList.get(50000);
        }
        System.out.println("LinkedList index access: " +
            (System.nanoTime() - start) / 1_000_000 + "ms");

        // Conclusion: use ArrayList in most cases
        // LinkedList only when frequent insert/delete at front/back
    }
}

List Sorting and Searching

Sorting with Collections utility and Comparator.

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class ListSortSearch {
    public static void main(String[] args) {
        List<Integer> numbers = new ArrayList<>(List.of(38, 27, 43, 3, 9, 82, 10));

        // Ascending sort
        Collections.sort(numbers);
        System.out.println("Ascending: " + numbers);

        // Descending sort
        numbers.sort(Comparator.reverseOrder());
        System.out.println("Descending: " + numbers);

        // String list sorting
        List<String> names = new ArrayList<>(List.of("Alice", "Charlie", "Bob", "Diana"));

        // Lexicographic sort
        Collections.sort(names);
        System.out.println("Alphabetical: " + names);

        // Sort by length
        names.sort(Comparator.comparingInt(String::length));
        System.out.println("By length: " + names);

        // Immutable list creation
        List<String> immutable = List.of("A", "B", "C");
        // immutable.add("D"); // UnsupportedOperationException!

        // Copying a list
        List<String> copied = new ArrayList<>(immutable);
        copied.add("D"); // OK

        // Useful methods
        System.out.println("Max: " + Collections.max(numbers));
        System.out.println("Min: " + Collections.min(numbers));
        System.out.println("Frequency: " + Collections.frequency(numbers, 10));

        // Sublist
        List<Integer> sub = numbers.subList(1, 4);
        System.out.println("Sublist: " + sub);
    }
}

Practical Example: Student Management System

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

record Student(String name, int score, String grade) implements Comparable<Student> {
    @Override
    public int compareTo(Student other) {
        return Integer.compare(other.score, this.score); // Descending by score
    }
}

public class StudentManager {
    private final List<Student> students = new ArrayList<>();

    void addStudent(String name, int score) {
        String grade = switch (score / 10) {
            case 10, 9 -> "A";
            case 8 -> "B";
            case 7 -> "C";
            default -> score >= 60 ? "D" : "F";
        };
        students.add(new Student(name, score, grade));
    }

    void printAll() {
        System.out.println("=== All Students ===");
        students.forEach(s ->
            System.out.printf("%-10s %3d pts (%s)%n", s.name(), s.score(), s.grade()));
    }

    void printSorted() {
        System.out.println("=== By Score ===");
        students.stream()
                .sorted()
                .forEach(s -> System.out.printf("%-10s %3d pts%n", s.name(), s.score()));
    }

    double getAverage() {
        return students.stream()
                .mapToInt(Student::score)
                .average()
                .orElse(0.0);
    }

    public static void main(String[] args) {
        StudentManager manager = new StudentManager();
        manager.addStudent("Alice", 85);
        manager.addStudent("Bob", 92);
        manager.addStudent("Charlie", 78);
        manager.addStudent("Diana", 95);
        manager.addStudent("Eve", 88);

        manager.printAll();
        manager.printSorted();
        System.out.printf("Overall average: %.1f pts%n", manager.getAverage());
    }
}

Today’s Exercises

  1. To-Do List Manager: Create a ToDo list using ArrayList. Implement add, delete (by index), mark as complete, print all items, and filter only completed items.

  2. Remove Duplicates: Write a method that removes duplicates from an integer list while maintaining the original order. (Implement using only List, without Set)

  3. Multi-Sort Students: Create Comparators to sort a Student object list by name, score, and grade respectively. Also implement a composite sort that sorts by name when scores are equal.

Was this article helpful?